#pragma once
#ifndef _SERIAL_PORT_H_
#define _SERIAL_PORT_H_
#ifdef WIN32
#pragma execution_character_set("utf-8")
#endif // WIN32

#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
#include<QtSerialPort/qserialport.h>

#include <qmutex.h>
#include <qdebug.h>
#include <qthread.h>
#include <QDateTime>
#include <qstring.h>
#include "common.h"
#include "utils.h"

typedef struct PortResponse_Struct {

    int code = -1;
    bool status = false;
    QByteArray data;

}PortResponse;

using namespace std;

/**
 * 串口数据传输对象
 */
class SerialPort : public QSerialPort {

    Q_OBJECT
private:
    QMutex mutex;
    QByteArray buffer;            //C串口接收到的缓冲字节数组
    const int MIN_DATA_LEN = 14;  //最小数组长度
public:

    SerialPort(QObject* parent = nullptr);

    ~SerialPort();

    /// <summary>
    /// 列出所有的串口号
    /// </summary>
    /// <param name="portList">输出所有串口名称</param>
    static void listPort(QStringList& portList);


    /// <summary>
    /// 打开串口
    /// </summary>
    /// <param name="comName">串口名称</param>
    /// <param name="baudRate">波特率</param>
    /// <returns></returns>
    bool openPort(const QString& port = "", int baudRate = 9600);

    /// <summary>
    /// 打开力矩伺服驱动串口
    /// </summary>
    /// <param name="port"></param>
    /// <param name="baudRate"></param>
    /// <returns></returns>
    bool openServoPort(const QString& port = "", int baudRate = 9600);


    /// <summary>
    /// 判断串口是否打开
    /// </summary>
    /// <returns></returns>
    bool isOpen();


    /// <summary>
    /// 关闭串口
    /// </summary>
    void close();

    /// <summary>
    /// 禁用/启用日志打印
    /// </summary>
    void enablePrintLogger(bool enable = true);

    /// <summary>
    /// 复位伺服
    /// </summary>
    void resetMotor();

    /// <summary>
    /// 握手指令
    /// </summary>
    bool shankeHands();

    /// <summary>
    /// 光源控制
    /// </summary>
    /// <param name="data">控制标识位</param>
    /// <returns></returns>
    bool lightControl(QByteArray& data);

    /// <summary>
    /// 激光器控制
    /// </summary>
    /// <param name="data">控制位标识</param>
    /// <returns></returns>
    bool laserControl(QByteArray& data);

    /// <summary>
    /// 主动轮控制
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    bool activeWheelControl(QByteArray& data);
    
    /// <summary>
    /// 被动轮控制
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    bool passiveWheelControl(QByteArray& data);

    /// <summary>
    /// 伺服控制
    /// </summary>
    /// <param name="data">伺服控制标识</param>
    /// <returns></returns>
    bool servoControl(QByteArray& data);


public:

    //复位
    vector<uchar>RESET = { 0x02,0xFF,0x31,0x30,0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x03,0x0D,0X0A };

    //握手
    vector<uchar>SHAKE_HANDS = { 0x02,0xFF,0x31,0x30,0x30,0x32,0x30,0x30,0x30,0x30,0x30,0x03,0x0D,0X0A };

    //光源控制
    vector<uchar> LIGHT_CONTROL = { 0x02,0xFF,0x31,0x30,0x30,0x33,0x30,0x30,0x31,0x31,0x38,0x38,0x03,0x0D,0x0A };//数据位1位（ 0x31 为开灯 0x30为关灯） 校验码两位 0x38（需要计算）

    //激光控制
    vector<uchar> LASER_CONTROL = { 0x02,0xFF,0x31,0x30,0x30,0x34,0x30,0x30,0x31,0x31,0x38,0x38,0x03,0x0D,0x0A };//数据位1位（ 0x31 为开激光 0x30为关激光） 校验码两位 0x38（需要计算）
    
    //主动轮控制
    vector<uchar> ACTIVE_WHEEL_CONTROL = { 0x02,0xFF,0x31,0x30,0x30,0x35,0x30,0x30,0x31,0x31,0x38,0x38,0x03,0x0D,0x0A };//数据位1位（ 0x31 为涨紧 0x32为松开） 

    //被动轮控制
    vector<uchar> PASSIVE_WHEEL_CONTROL = { 0x02,0xFF,0x31,0x30,0x30,0x36,0x30,0x30,0x31,0x31,0x38,0x38,0x03,0x0D,0x0A };//数据位1位（ 0x31 为涨紧 0x32为松)


    //伺服控制                 
    /*************************************************
    * 数据1：31：力矩控制  32：圈数控制                *
    * 当数据1为31时，数据2：31：正转 32：反转 33：停    *
    * 当数据1为32时，数据2：31：开始转圈 32：停止       *
    **************************************************/
    vector<uchar> SERVO_CONTROL = { 0x02,0xFF,0x31,0x30,0x30,0x37,0x30,0x30,0x32,0x31,0x31,0x38,0x38,0x03,0x0D,0x0A};////数据位2位（0x31 0x31） 校验码两位 0x38（需要计算）

protected:

    /// <summary>
    /// 向串口发送字符串数据
    /// </summary>
    /// <param name="data"></param>
    void sendData(const vector<uchar>& data);

    unsigned char* floatToBytes(float value);

    uint16_t crc16_ccitt(const std::vector<unsigned char>& data);

    /// <summary>
    /// 计算校验码
    /// </summary>
    /// <param name="data">指令数据</param>
    /// <returns></returns>
    ushort calculataCheckCode(QByteArray& data);

    /// <summary>
    /// 检查校验码
    /// </summary>
    /// <param name="data">指令数据</param>
    /// <returns></returns>
    bool compareCheckCode(QByteArray& data);

    /// <summary>
    /// 填充校验码
    /// </summary>
    /// <param name="data">指令数据</param>
    void fillCheckCode(QByteArray& data);

    /// <summary>
    /// 读取串口数据
    /// </summary>
    /// <param name="timeout">超时时间</param>
    /// <returns></returns>
    PortResponse readDataImmdiately(int timeout = 15000);

    /// <summary>
    /// 解析串口数据
    /// </summary>
    /// <param name="data">串口数据</param>
    /// <returns></returns>
    PortResponse parseData(QByteArray& data);

    /// <summary>
    /// 发送串口数据 数据内容是char类型数组
    /// </summary>
    /// <param name="data"></param>
    void sendDataC(vector<uchar>& data);

    /// <summary>
    /// 发送串口数据
    /// </summary>
    /// <param name="data"></param>
    void sendDataB(const QByteArray& data);

    /// <summary>
    /// 将vector<uchar>转换为QByteArray
    /// </summary>
    /// <param name="data"></param>
    /// <param name="buffer"></param>
    void vector2ByteArray(vector<uchar>& data, QByteArray& buffer);

signals:

    void ParseDataFinish(QString functionCode, QString data);

    void sgn_ackRight();//正确响应信号


protected:
       
    //是否打印日志
    bool m_printMsg;

    //操作串口的对象
    QSerialPort m_port, m_servo_port;

    //串口类
    QString m_num,m_servo_num;

};


/// <summary>
/// 485通信，控制移动平台以及光源
/// </summary>
class RS485Port : public SerialPort {

    Q_OBJECT

public:

    //光源选择
    enum Light {

        TOP = 4,        //顶灯

        SLIDER = 1,     //侧灯

        BOTTOM = 2,     //底灯

        ALL = 7         //所有    
    };


    //滑台位置
    enum MoveDirection {

        POS_RESET = 0,   //复位

        POS_TAIL = 1,    //向后

        UNABLE_LOCATE = 2,  //无法定位

    };


    RS485Port(QObject* parent = nullptr);

    /// <summary>
    /// 设置步进电机运动方式
    /// </summary>
    /// <returns></returns>
    void initRunModel();

    /// <summary>
    /// 设置3和4传感器的输入模式
    /// </summary>
    void set3and4inputMode();

    /// <summary>
    /// 设置传感器3和4内部上拉
    /// </summary>
    void setSensorInternalPullUp();


    /// <summary>
    /// 传感器3下降沿立刻停止
    /// </summary>
    void sensor3FallingEdgeDecelerateStop();

    /// <summary>
   /// 传感器4下降沿立刻停止
   /// </summary>
    void sensor4FallingEdgeDecelerateStop();

    /// <summary>
    /// 初始化运行参数
    /// </summary>
    /// <param name="aPlus">加速度</param>
    /// <param name="aReduce">减速度</param>
    /// <param name="Equicken">加速电流</param>
    /// <param name="Ework">运行电流</param>
    /// <param name="Ework">保持电流</param>
    /// <param name="mcs">细分</param>
    void updateParams(const SerialPortConfig& config);


    /// <summary>
    /// 电机使能
    /// </summary>
    void motorEnabling();


    /// <summary>
    /// 电机失能
    /// </summary>
    void motorDisabling();


    /// <summary>
    /// 设置步进电机的速度
    /// </summary>
    /// <param name="speed"></param>
    void setMotoSpeed(float speed = 16000);


    /// <summary>
    /// 紧急停止电机运动
    /// </summary>
    void stopMotor();


    /// <summary>
    /// 获取电机位置，0：起始位置，1：末尾位置，2：中间， -1：异常位置
    /// </summary>
    /// <returns></returns>
    int getMotorPos();


    /// <summary>
    /// 移动电机
    /// </summary>
    /// <param name="speed">电机移动的速度</param>
    /// <param name="step">移动步数，正负表示方向，负数表示复位的方向</param>s
    void moveMoto(float speed = 64000, int step = 200000);


    /// <summary>
    /// 复位电机
    /// </summary>
    /// <param name="waitReset">是否等待复位完成</param>
    /// <returns></returns>
    void resetMoto(float speed = 20000.0f, bool waitReset = true);


    /// <summary>
    /// 将电机移动到末尾
    /// </summary>
    /// <returns></returns>
    /// std::function<void()> fun是C++11引入的一个泛型函数封装器，用于存储可调用的对象（函数、lambda表达式、函数对象）
    /// void()表示std::function对象，fun是一个参数且无返回值的函数，fun表示一个回调函数
    void moveMotoToTail(std::function<void()> fun, float speed = 10000);


    /// <summary>
    /// 开灯
    /// </summary>
    /// <param name="num"></param>
    /// <returns></returns>
    void ledOn(int num);

    /// <summary>
    /// 关灯
    /// </summary>
    /// <param name="num"></param>
    /// <returns></returns>
    void ledOff(int num);

    /// <summary>
    /// 读取数据
    /// </summary>
    /// <param name="byteCount">读取的数据个数</param>
    /// <param name="timeout">超时时间</param>
    /// <returns></returns>
    QByteArray readData(int byteCount, int timeout = 2000);


private:

    int m_step = 400000;

};

/// <summary>
/// 
/// </summary>
class RS232Port : public SerialPort {

    Q_OBJECT

signals:

    void uploadData(QString data);

public:

    RS232Port(QObject* parent = nullptr);

private slots:

    void onDataArrive();


};



#endif